package c05面向对象;

import java.util.Iterator;

interface IfEnum {
	void m();
}

public class 枚举类探究 {

	//枚举其实是一种特殊的类，编译时会产生一个Season.class文件！
	public enum Season {
		//枚举类的所有实例必须写在第一行，否则编译出错
		spring, summer, fall, winter;
		//以上代码实际上等价于：public static final Season spring=new Season();......（虽然等价，但是不能这么写！）
		//       public static final Season spring=new Season();//编译错误！
		//如果显示定义了带参构造器，比如 Season(String s) 那么列举实例时必须形如 spring("xxx"),......的格式。

		//枚举类也是类，一样可以定义Field、方法、初始化块、构造器
		private int i;

		public int getI() {
			return i;
		}

		public void setI(int i) {
			this.i = i;
		}

		{
			//比构造器先执行！
			System.err.println("代码块");
			i = 1;
		}

		static {
			//@@初始化块、构造器执行完后才执行！！！
			System.err.println("静态代码块");
		}

		//构造器只能是private的！只能被类内部调用！
		private Season() {
			System.err.println("调用了Season构造器...");
		}
	}

	//枚举类一样可以实现接口！但是必须实现接口的方法而不能定义为抽象类！
	public enum Season2 implements IfEnum {
//		spring, summer, fall, winter;
//		//这种重写方式使得每个枚举类实例的m方法都一样，
//		@Override
//		public void m() {}

		//但是枚举类可以使用匿名内部子类的方式来为每个实例重写不同的m方法：
		//花括号实际上是内部子类的类体部分。除此之外，也可以在枚举类里定义一个抽象方法，然后在每个实例后实现
		//为什么可以定义子类？因为只有非抽象的枚举类才会带final，抽象枚举类没有final，所以可以被继承！
		spring {
			@Override
			public void m() {
				System.err.print("spring");
			}
		},
		summer {
			@Override
			public void m() {
				System.err.print("summer");
			}
		},
		fall {
			@Override
			public void m() {
				System.err.print("fall");
			}
		},
		winter {
			@Override
			public void m() {
				System.err.print("winter");
			}
		};
	}

	//枚举类不能被继承！！因为非抽象枚举类默认被final修饰。
//	public enum Season3 extends Season2{}

	public static void switchCase(Season s) {
		switch (s) {
			case spring://只有在case后面才可以省略枚举类前缀！
				System.err.println(Season.spring);//其他地方必须带上枚举类前缀！
				//System.err.println(spring);//编译错误！
				break;
			case summer:
				System.err.println(Season.summer);
				break;
			case fall:
				System.err.println(Season.fall);
				break;
			case winter:
				System.err.println(Season.winter);
				break;
		}
	}

	public static void main(String[] args) {
		//只能通过枚举类的静态方法valueOf来创建实例！如果传入了非法字符串将会引发IllegalArgumentException。
		Season season = Season.valueOf(Season.class, "fall");
		//new Season();//编译错误！
		switchCase(season);
		System.err.println(season.getI());

		switchCase(Season.spring);

		for (Season2 s : Season2.values()) {//返回枚举类的所有实例
			s.m();//将会看到每个枚举实例的m方法都不一样！！
			System.err.print("," + s.ordinal() + ",");//索引，从0开始
			System.err.print(s + ",");//调用toString方法，比name方法更好
			System.err.print(s.name() + ",");//枚举名称
			System.err.print(s.compareTo(Season2.spring) + "\n");//比较顺序，因为索引是递增的，所以后面的枚举比前面的大，返回正整数
		}
	}

}
